<?php

include_file('src/02_class/ALog.abstract_class.php');

/**
 * LogManager - Main class for logging event about job and others
 * 
 * @author polux
 * @final 
 */
final class LogManager {

	// ******************************** Attributes ******************************** //
	/**
	 * Output Streams to write log
	 * 
	 * @var array(mixed)
	 * @access protected
	 */
	protected $_ao_outputstream;
	/**
	 * Logged stuff
	 *
	 * @var array(ALog)
	 * @access protected
	 */
	protected $_ao_logs;
	/**
	 * Exception logged
	 *
	 * @var array(Exception)
	 * @access protected
	 */
	protected $_ao_exceptions;	
	
	// ******************************** Constructor ******************************** //
	/**
	 * Class default constructor
	 */
	function __construct() {
		$this->_ao_exceptions = array();
		$this->_ao_logs = array();
		$this->_ao_outputstream = array();
	}
	
	// ******************************** Public Methods ******************************** //
	/**
	 * addLogObject - Adding a log object to LogManager collection
	 * 
	 * @param ALog 	$p_o_logObject	Log object to register
	 */
	private function addLogObject(ALog &$p_o_logObject)
	{
		$this->_ao_logs[$p_o_logObject->getTimestamp()][] = array($p_o_logObject);
		$p_o_logObject->registerLogManager($this);
	}
	/**
	 * addLogInformation - Create and a log about an information
	 *  
	 * @param AJob		$p_o_obj
	 * @param string 	$p_s_msg
	 */
	public function addLogInformation($p_o_obj,$p_s_msg)
	{
		$l_o_logInfo = new LogInfo($p_o_obj, $p_s_msg);
		$this->addLogObject($l_o_logInfo);
	}	
	/**
	 * addLogWarning - Create and a log about a warning
	 *
	 * @param AJob		$p_o_obj
	 * @param string 	$p_s_msg
	 */
	public function addLogWarning($p_o_obj,$p_s_msg)
	{
		$l_o_logWarn = new LogWarn($p_o_obj, $p_s_msg);
		$this->addLogObject($l_o_logWarn);
	}
	/**
	 * addLogError - Create and a log about an error
	 *
	 * @param AJob		$p_o_obj
	 * @param string 	$p_s_msg
	 */
	public function addLogError($p_o_obj,$p_s_msg)
	{
		$l_o_logErr = new LogError($p_o_obj, $p_s_msg);
		$this->addLogObject($l_o_logErr);
	}
	/**
	 * addLogBreak
	 */	
	public function addLogBreak()
	{
		$l_o_logBr = new LogBreak();
		$this->addLogObject($l_o_logBr);
	}
	/**
	 * addLogTitle
	 * 
	 * @param string $p_s_title
	 */
	public function addLogTitle($p_s_title)
	{
		$l_o_logBr = new LogTitle($p_s_title);
		$this->addLogObject($l_o_logBr);
	}
	/**
	 * addLogSubTitle
	 * 
	 * @param string $p_s_title
	 */
	public function addLogSubTitle($p_s_title)
	{
		$l_o_logBr = new LogSubTitle($p_s_title);
		$this->addLogObject($l_o_logBr);
	}
	/**
	 * Flush log event 
	 * 
	 * @param string $p_s_outputStream
	 */
	private function flushNewLogsTo($p_s_outputStream)
	{
		try 
		{
			$l_o_handler = fopen($p_s_outputStream,'a');
			
			foreach($this->_ao_logs as $l_stime_key => $l_ao_logObject)
			{
				foreach($l_ao_logObject as $l_s_key => $l_o_logObject)
				{
					if($l_o_logObject[0] instanceof ALog)
					{
						if(!array_key_exists($p_s_outputStream, $this->_ao_logs[$l_stime_key][$l_s_key]) || (array_key_exists($p_s_outputStream, $this->_ao_logs[$l_stime_key][$l_s_key]) && $this->_ao_logs[$l_stime_key][$l_s_key][$p_s_outputStream] == false))
						{
							fwrite($l_o_handler,$l_o_logObject[0]->getFormattedLogMessage()."\n");
							// Flag this outputstream have already this log Item
							$this->_ao_logs[$l_stime_key][$l_s_key][$p_s_outputStream] = true;
						}
					}
				}
			}

			fclose($l_o_handler);
			
		}
		catch(Exception $e)
		{
			throw new LogStreamAccessException("Exception during flush logs items ! Msg : ".$e->getMessage());
		}		
	}
	/**
	 * Flush all log items on specified output
	 *
	 * @param 	string 		$p_s_outputStream
	 * @access 	private
	 */
	private function flushAllLogsTo($p_s_outputStream)
	{
		try
		{
			// Opening stream
			$l_o_handler = fopen($p_s_outputStream,'a');

			// echo "on passe dans le rendu 1\n";
			// For each log object (organized by timestamp)
			foreach($this->_ao_logs as $l_stime_key => $l_ao_logObject)
			{
				// For each log object
				foreach($l_ao_logObject as $l_s_key => $l_o_logObject)
				{
					if($l_o_logObject[0] instanceof ALog )
					{
						// Writting Log Object Message to OutputStream						
						fwrite($l_o_handler,$l_o_logObject[0]->getFormattedLogMessage()."\n");					
						// Flag this outputstream have already this log Item
						$this->_ao_logs[$l_stime_key][$l_s_key][$p_s_outputStream] = true;						
					}
				}
			}
			
			// Closing Handler
			fclose($l_o_handler);				
		}
		catch(Exception $e)
		{
			throw new LogStreamAccessException("Exception during flush logs items ! Msg : ".$e->getMessage());
		}		
	}
	/**
	 * Flush all to stdout
	 */
	public function flushAllLogsToStdout()
	{
		$this->flushAllLogsToStream('STDOUT');
	}
	/**
	 * Flush all to specified stream
	 * 
	 * @param string 	$p_s_outputStream
	 * @throws LogGenericException
	 */
	public function flushAllLogsToStream($p_s_outputStream)
	{
		if(array_key_exists($p_s_outputStream,$this->_ao_outputstream))
		{
			$this->flushAllLogsTo($this->_ao_outputstream[$p_s_outputStream]);
		}
		else 
			throw new LogGenericException("Output stream '$p_s_outputStream' not declared. Flush not executed.");		
	}
	/**
	 * Flush for all stream 
	 *
	 * @param string 	$p_s_outputStream
	 * @throws LogGenericException
	 */
	public function flushAllLogsOnAllStream()
	{
		foreach($this->_ao_outputstream as $l_s_output)
		{
			$this->flushAllLogsTo($l_s_output);
		}
	}
	/**
	 * Flush for all stream
	 *
	 * @param string 	$p_s_outputStream
	 * @throws LogGenericException
	 */
	public function flushNewLogsOnAllStream()
	{
		foreach($this->_ao_outputstream as $l_s_output)
		{
			$this->flushNewLogsTo($l_s_output);
		}
	}
	/**
	 * Flush new log to specified stream
	 *
	 * @param string 	$p_s_outputStream
	 * @throws LogGenericException
	 */
	public function flushNewLogsToStream($p_s_outputStream)
	{
		if(array_key_exists($p_s_outputStream,$this->_ao_outputstream))
		{
			$this->flushNewLogsTo($this->_ao_outputstream[$p_s_outputStream]);
		}
		else
			throw new LogGenericException("Output stream '$p_s_outputStream' not declared. Flush not executed.");
	}
	
	
	
	/**
	 * setOutputStream - Add an ouput stream
	 * 
	 * @param string	$p_s_lib
	 * @param string	$p_x_outputStream
	 */
	public function setOutputStream($p_s_lib,$p_x_outputStream)
	{
		if(!is_null($p_x_outputStream))
			$this->_ao_outputstream[$p_s_lib] = $p_x_outputStream;
	}
}

?>